#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using GameStateManagement;
using SpriterRuntime;
using Microsoft.Xna.Framework.Input.Touch;
using GameStateManagementSample.Classes;
using System.Linq;
using System.Collections.Generic;
//using Poly2Tri;
#endregion

namespace GameStateManagementSample
{
    /// <summary>
    /// This screen implements the actual game logic. It is just a
    /// placeholder to get the idea across: you'll probably want to
    /// put some more interesting gameplay in here!
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        ContentManager content;
        SpriteFont gameFont;
        Texture2D background;
        //Vector2 playerPosition = new Vector2(100, 100);
        Vector2 enemyPosition = new Vector2(100, 100);
        SpriterCharacter spider;
        SmoothPath spiderPath;

        SpiderArea spiderArea;
        EnemyArea enemyArea;

        Route routeToPathStart;

        bool walKToPathStart = false;

        Random random = new Random();

        float pauseAlpha;

        InputAction pauseAction;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            pauseAction = new InputAction(
                new Buttons[] { Buttons.Start, Buttons.Back },
                new Keys[] { Keys.Escape },
                true);

            // Vector2 a = new Vector2(430f, 354.2909f);
            // Vector2 b = new Vector2(430f,750f);
            // Vector2 c = new Vector2(273f,411f);
            // Vector2 d = new Vector2(323f, 409f);
            //var m =  GeometryHelper.GetTrajectoryIntersectionOnLine(a, b, c, d);
            //var n = GeometryHelper.GetTrajectoryIntersectionOnLineDouble(a, b, c, d);
        }


        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void Activate(bool instancePreserved)
        {
            if (!instancePreserved)
            {
                if (content == null)
                    content = new ContentManager(ScreenManager.Game.Services, "Content");

                gameFont = content.Load<SpriteFont>("gamefont");
                background = content.Load<Texture2D>("level");
                SpriterData data = content.Load<SpriterData>("characters/voras/voras_walk");
                Texture2D bone = content.Load<Texture2D>("bone");

                spiderPath = new SmoothPath(content);
                spider = new SpriterCharacter(data, content, bone);
                spider.Position = new Vector2(ScreenManager.GraphicsDevice.Viewport.Width / 2, 50);

                spider.CurrentSequence = 1;
                LineBatchTester.LineBatch.Init(ScreenManager.GraphicsDevice);

                spiderArea = new SpiderArea(content);
                enemyArea = new EnemyArea();
                routeToPathStart = new Route();
                List<Vector2> p = new List<Vector2>();
                float margin = 50f;
                p.Add(new Vector2(margin, margin));
                p.Add(new Vector2(ScreenManager.GraphicsDevice.Viewport.Width - margin, margin));
                p.Add(new Vector2(ScreenManager.GraphicsDevice.Viewport.Width - margin, ScreenManager.GraphicsDevice.Viewport.Height - margin));
                p.Add(new Vector2(margin, ScreenManager.GraphicsDevice.Viewport.Height - margin));
                //var p = new Polygon(points);
                //P2T.Triangulate(p);
                enemyArea.SetArea(p);

                // A real game would probably have more content than this sample, so
                // it would take longer to load. We simulate that by delaying for a
                // while, giving you a chance to admire the beautiful loading screen.
                //Thread.Sleep(1000);

                // once the load has finished, we use ResetElapsedTime to tell the game's
                // timing mechanism that we have just finished a very long frame, and that
                // it should not try to catch up.
                ScreenManager.Game.ResetElapsedTime();
            }

#if WINDOWS_PHONE
            if (Microsoft.Phone.Shell.PhoneApplicationService.Current.State.ContainsKey("PlayerPosition"))
            {
                // playerPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"];
                enemyPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"];
            }
#endif
        }


        public override void Deactivate()
        {
#if WINDOWS_PHONE
            // Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"] = playerPosition;
            Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"] = enemyPosition;
#endif

            base.Deactivate();
        }


        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void Unload()
        {
            content.Unload();

#if WINDOWS_PHONE
            // Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("PlayerPosition");
            Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("EnemyPosition");
#endif
        }


        #endregion

        #region Update and Draw

        enum Mode 
        {
            walk,
            draw
        }
        Mode mode;
        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

            if (IsActive)
            {


                // Apply some random jitter to make the enemy move around.
                const float randomization = 10;

                enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
                enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;

                // Apply a stabilizing force to stop the enemy moving off the screen.

                // TODO: this game isn't very fun! You could probably improve
                // it by inserting something more interesting in this space :-)

                Vector2 targetPosition = new Vector2(
                    ScreenManager.GraphicsDevice.Viewport.Width / 2 - gameFont.MeasureString("Insert Gameplay Here").X / 2,
                    200);

                enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
                if (mode == Mode.walk)
                {
                    if (walk && spiderPath.pathPoints.Count > 1)
                    {
                        if (walkStartTime == TimeSpan.Zero) walkStartTime = gameTime.TotalGameTime;
                        distanceWalked = WalkSpeed * (float)(gameTime.TotalGameTime - walkStartTime).TotalMilliseconds;
                        DirectionPoint dp = spiderPath.GetPositionAtLength(distanceWalked);
                        spider.Position = dp.Position;
                        spider.Rotation = dp.Rotation - MathHelper.PiOver2;
                        if (distanceWalked >= pathlength)
                        {
                            distanceWalked = 0;
                            walk = false;
                            SplitPaths();
                            spiderPath.pathPoints.Clear();
                            // walkStartTime = gameTime.TotalGameTime;
                        }

                    }
                    
                }
                else
                {
                    if (walk && spiderPath.pathPoints.Count > 1)
                    {

                        walk = false;
                        SplitPaths();
                        spiderPath.pathPoints.Clear();
                        // walkStartTime = gameTime.TotalGameTime;
                    }
                }

                if (spider.Position.X == -1)
                {
                    spider.Position = new Vector2(240, 50);
                    spider.Rotation = 0;
                }

                spider.Update(gameTime);

            }
        }
        float distanceWalked;
        float WalkSpeed = 0.2f;
        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(GameTime gameTime, InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            PlayerIndex player;
            if (pauseAction.Evaluate(input, ControllingPlayer, out player) || gamePadDisconnected)
            {
#if WINDOWS_PHONE
                ScreenManager.AddScreen(new PhonePauseScreen(), ControllingPlayer);
#else
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
#endif
            }
            else
            {
                // Otherwise move the player position.
                Vector2 movement = Vector2.Zero;
                float rotation = 0;
                if (keyboardState.IsKeyDown(Keys.Left))
                    movement.X--;

                if (keyboardState.IsKeyDown(Keys.Right))
                    movement.X++;

                if (keyboardState.IsKeyDown(Keys.Up))
                    movement.Y--;

                if (keyboardState.IsKeyDown(Keys.Down))
                    movement.Y++;

                Vector2 thumbstick = gamePadState.ThumbSticks.Left;

                movement.X += thumbstick.X;
                movement.Y -= thumbstick.Y;

                //if (input.TouchState.Count > 0)
                //{
                //    Vector2 touchPosition = input.TouchState[0].Position;
                //    Vector2 direction = touchPosition - spider.Position;
                //    direction.Normalize();
                //    movement += direction;

                //    rotation = GeometryHelper.VectorToAngle(direction) + MathHelper.Pi;
                //}

                //if (movement.Length() > 1)
                //    movement.Normalize();
                //spider.Rotation = rotation;
                //spider.Position += movement * 8f;

                ProcessTouch(input);
                if (spiderPath.pathPoints.Count > 0)
                {

                }

            }
        }
        TimeSpan walkStartTime;
        bool walk = false;
        float pathlength = 0;

        void ProcessTouch(InputState input)
        {

            TouchCollection _currentMouseState = input.TouchState;
            if (_currentMouseState.Count == 1)
            {
                TouchLocation tl = _currentMouseState[0];
                if (tl.State == TouchLocationState.Pressed)
                {
                    walk = false;
                    walkStartTime = TimeSpan.Zero;

                    spiderPath.pathPoints.Clear();
                    if (enemyArea.HitTest(tl.Position))
                    {
                        if (enemyArea.PointOnBorder(tl.Position))
                            spiderPath.pathPoints.Add(tl.Position);
                        else
                        {
                            var pt = enemyArea.GetClosestPointOnAreaBorder(tl.Position);
                            if (pt != -Vector2.One)
                            {
                                spiderPath.pathPoints.Add(pt);

                            }
                            //spiderPath.pathPoints.Add(tl.Position);
                        }
                        // routeToPathStart = new Route(spider.Position, enemyArea.getPointNormalOffset(spiderPath.pathPoints.First(), 30), enemyArea);
                    }
                }

                if (tl.State == TouchLocationState.Moved)
                {
                    if (enemyArea.HitTest(tl.Position))
                    {
                        if (spiderPath.pathPoints.Count == 0)
                        {
                            if (enemyArea.PointOnBorder(tl.Position))
                                spiderPath.pathPoints.Add(tl.Position);
                            else
                            {
                                var pt = enemyArea.GetClosestPointOnAreaBorder(tl.Position);
                                if (pt != -Vector2.One)
                                {
                                    spiderPath.pathPoints.Add(pt);

                                }
                                // spiderPath.pathPoints.Add(tl.Position);
                            }
                        }
                        else
                        {
                            var last = spiderPath.pathPoints.Last();
                            var v = spiderPath.pathPoints.FirstOrDefault(x => Vector2.Distance(x, tl.Position) < 40 && x != last);

                            //var v = vectors.LastOrDefault(x => Vector2.Distance(x, tl.Position) < 40 && x != peek);
                            if (v != null && spiderPath.pathPoints.Count > 1 && spiderPath.pathPoints.Contains(v))
                            {
                                //while (spiderPath.pathPoints.Last() != v)
                                //{
                                spiderPath.pathPoints.RemoveRange(spiderPath.pathPoints.IndexOf(v), spiderPath.pathPoints.Count - spiderPath.pathPoints.IndexOf(v));
                                //}
                            }
                            if ((spiderPath.pathPoints.Count > 0 && Vector2.Distance(spiderPath.pathPoints.Last(), tl.Position) > 50) || spiderPath.pathPoints.Count == 0)
                            {

                                spiderPath.pathPoints.Add(tl.Position);

                            }
                        }
                    }
                    else
                    {
                        if (spiderPath.pathPoints.Count >= 2 && !enemyArea.PointOnBorder(spiderPath.pathPoints.Last()))
                        {
                            var pt = enemyArea.GetTrajectoryIntersection(spiderPath.pathPoints[spiderPath.pathPoints.Count - 2], spiderPath.pathPoints[spiderPath.pathPoints.Count - 1]);
                            if (pt != -Vector2.One)
                            {
                                spiderPath.pathPoints.Add(pt);
                                // SplitPaths();
                            }
                            //  spiderPath.pathPoints.Clear();
                        }
                        else
                            if (spiderPath.pathPoints.Count == 1)
                            {
                                var pt = enemyArea.GetClosestPointOnAreaBorder(tl.Position);
                                if (pt != -Vector2.One)
                                {
                                    spiderPath.pathPoints.Add(pt);
                                    //  SplitPaths();
                                }
                                // spiderPath.pathPoints.Clear();
                            }

                        if (spiderPath.pathPoints.Count >= 2 && !walk)
                        {
                            if (enemyArea.PointOnBorder(spiderPath.pathPoints.First()) && enemyArea.PointOnBorder(spiderPath.pathPoints.Last()))
                            {
                                walk = true;
                                pathlength = spiderPath.GetPathLength();
                            }
                        }
                        else walk = false;
                    }
                }

                if (tl.State == TouchLocationState.Released)
                {
                    if (spiderPath.pathPoints.Count > 2)
                    {
                        if (enemyArea.HitTest(tl.Position))
                        {
                            if (enemyArea.PointOnBorder(tl.Position))
                            {
                                spiderPath.pathPoints.Add(tl.Position);
                            }
                            else
                            {
                                var pt = enemyArea.GetTrajectoryIntersection(spiderPath.pathPoints[spiderPath.pathPoints.Count - 2], spiderPath.pathPoints[spiderPath.pathPoints.Count - 1]);
                                if (pt != -Vector2.One)
                                {
                                    spiderPath.pathPoints.Add(tl.Position);
                                    spiderPath.pathPoints.Add(pt);
                                    // SplitPaths();
                                }
                                // spiderPath.pathPoints.Clear();
                            }
                        }
                        else
                        {
                            var pt = enemyArea.GetTrajectoryIntersection(spiderPath.pathPoints[spiderPath.pathPoints.Count - 2], spiderPath.pathPoints[spiderPath.pathPoints.Count - 1]);
                            if (pt != -Vector2.One)
                            {
                                spiderPath.pathPoints.Add(pt);
                                //SplitPaths();
                            }
                            //spiderPath.pathPoints.Clear();
                        }



                    }
                    if (!walk && spiderPath.pathPoints.Count > 2)
                    {
                        if (enemyArea.PointOnBorder(spiderPath.pathPoints.First()) && enemyArea.PointOnBorder(spiderPath.pathPoints.Last()))
                        {
                            walk = true;
                            pathlength = spiderPath.GetPathLength();
                        }
                    }
                    else walk = false;
                    //vectors.Clear();
                }


            }
            //_lastMouseState = _currentMouseState;

        }
        void SplitPaths()
        {
            //PolygonPoint[] pp = new PolygonPoint[4];
            //pp[0] = new PolygonPoint(430, 299.7451171875);
            //pp[1] = new PolygonPoint(430,750);
            //pp[2] = new PolygonPoint(50,750);
            //pp[3] = new PolygonPoint(50, 253);

            //        Polygon test = new Polygon(pp);
            //        P2T.Triangulate(test);

            if (spiderPath.pathPoints.Count < 3) return;
            List<Vector2> p1, p2;
            try
            {
                enemyArea.SplitArea(spiderPath, out p1, out p2);
                //P2T.Triangulate(p1);
                //P2T.Triangulate(p2);
            }
            catch (Exception ex)
            {

                enemyArea.SplitArea(spiderPath, out p1, out p2);
                //P2T.Triangulate(p1);
                //P2T.Triangulate(p2);
            }
            try
            {
                var a1 = GeometryHelper.GetPolyArea(p1);
                var a2 = GeometryHelper.GetPolyArea(p2);
                if (a1 > a2)
                {
                    enemyArea.SetArea(p1);
                    spiderArea.AddPolygon(p2);
                }
                else
                {
                    enemyArea.SetArea(p2);
                    spiderArea.AddPolygon(p1);
                }
            }
            catch (Exception ex)
            {
                var a1 = GeometryHelper.GetPolyArea(p1);
                var a2 = GeometryHelper.GetPolyArea(p2);
                if (a1 > a2)
                {
                    enemyArea.SetArea(p1);
                    spiderArea.AddPolygon(p2);
                }
                else
                {
                    enemyArea.SetArea(p2);
                    spiderArea.AddPolygon(p1);
                }
                var asd = "";
                //P2T.Triangulate(p1);
                //P2T.Triangulate(p2);
            }

        }
        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            // This game has a blue background. Why? Because!
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                               Color.CornflowerBlue, 0, 0);

            // Our player and enemy are both actually just text strings.
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, RasterizerState.CullNone);

            spriteBatch.Draw(background, new Rectangle(0, 0, 480, 800), Color.White);
 
            // spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);

            //spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
            //                       enemyPosition, Color.DarkRed);
            enemyArea.Draw(spriteBatch);
            spiderArea.Draw(spriteBatch);
            spiderPath.Draw(spriteBatch);
            routeToPathStart.Draw(spriteBatch);

            spider.Draw(spriteBatch);
            DebugRuler.DrawRuler(this);
            spriteBatch.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0 || pauseAlpha > 0)
            {
                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                ScreenManager.FadeBackBufferToBlack(alpha);
            }
        }


        #endregion
    }
}
